---
id: dbcontext-db-first
title: 9.19 数据库生成模型
sidebar_label: 9.19 数据库生成模型 (Db First)
---

import useBaseUrl from "@docusaurus/useBaseUrl";

:::tip 关于脚本

在阅读下面文档之前，必须把`Furion` 源码文件夹下的 `tools/cli.ps1` 文件拷贝到本地中。而且 `Fur.Web.Entry` 层需要安装 `Microsoft.EntityFrameworkCore.Tools` 包。

:::

:::important 系统提示禁止运行脚本解决

如果出现 `cli.ps1` 无法运行的情况，如提示：`“因为在此系统上禁止运行脚本”`，只需要打开系统管理员 `CMD/Powershell` 执行：`set-ExecutionPolicy RemoteSigned` 命令并根据操作提示输入 `A` 即可。

之后重启 `Visual Studio` 工具。

:::

## 9.19.1 数据库开发方式

`Furion` 提供两种主要方法来 **保持实体模型和数据库架构同步**。

至于我们应该选用哪个方法，请确定你是希望以实体模型为准还是以数据库为准：

- 如果希望 **以实体模型为准**，请使用正向工程（Code First）。 对实体模型进行更改时，此方法会以增量方式将相应架构更改应用到数据库，以使数据库保持与实体模型兼容。

- 如果希望 **以数据库架构为准**，请使用反向工程（Database First）。 使用此方法，可通过将数据库架构反向工程到实体模型来生成相应的实体类型。

本章节是 **反向工程（Database First）** 的相关内容。

## 9.19.2 操作指南

:::important 操作之前注意事项

目前 `Furion Tools` 生成工具**默认不支持任何数据库**生成，所以如需生成特定数据库的代码，只需要在 `Furion.EntityFrameworkCore.Core` 安装对应的数据库包即可：

各个数据库的包可查阅：[多数据库操作-数据库提供器对应包](dbcontext-multi-database)

另外，只有 `SqlServer` 数据库支持可视化 `GUI` 操作，其他的只能命令行操作。

:::

### 9.19.2.1 打开 `程序包管理控制台`

注意：开始之前先把 `Furion.Web.Entry` 设为启动项目。

<img src={useBaseUrl("img/dbfirst1.png")} />

### 9.19.2.2 切换默认项目

将 `程序包管理控制台` 默认项目设置为 `Furion.Core`，如果您是其他名字，则切换对应即可。

<img src={useBaseUrl("img/dbfirst2.png")} />

### 9.19.2.3 输入 `cli.ps1` 命令

```shell
 &"../tools/cli.ps1" -DbProvider "EFCore数据库程序集名" -CoreProject "你的Core层" -EntryProject "你的启动层" -ConnectionName "连接字符串的 [key]"
```

:::note 小提示

如果使用的是 `SqlServer` 数据库，则默认不需要指定 `-DbProvider` 参数。

:::

如果不清楚当前运行环境的路径，可以输入 `pwd` 查看。

:::important 关于数据库命名

如果需要保持和数据库一模一样的命名，则使用 `-UseDatabaseNames` 参数指定，如：

```cs
 &"../tools/cli.ps1" -UseDatabaseNames
```

:::

<img src={useBaseUrl("img/dbfirst3.png")} />

:::important 等待输入

执行上面命令后，此时 `Cli` 有一个等待输入提示：

```shell
Furion Tools v1.0.0 请键入操作类型：[G] 界面操作，[任意字符] 命令行操作
Furion Tools v1.0.0 您的输入是:
```

**输入大写 `G` 进入界面操作模式，其他任意字符进入命令行操作模式。**

:::

:::caution 注意事项

目前只有 `Sql Server` 数据库才支持 `GUI 界面操作模式`，其他数据库请使用命令行模式。

:::

## 9.19.3 界面操作模式

### 9.19.3.1 启动界面操作

当我们输入 `G` 时，将打开 `GUI` 界面操作模式，如：

<img src={useBaseUrl("img/dbfirst4.png")} />

这时，`Furion Tools` 会自动查找所有数据库配置连接字符串的 `.json` 文件：

:::important 注意事项

数据库连接字符串配置项需写到 `json` 配置文件中，且根节点需要写为 `ConnectionStrings` 。

:::

```json {12-13}
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DbConnectionString": "Server=localhost;Database=Furion;User=sa;Password=000000;MultipleActiveResultSets=True;",
    "Sqlite3ConnectionString": "Data Source=./Furion.db"
  }
}
```

### 9.19.3.2 加载数据库表

选择连接字符串之后，点击 `加载数据库表和视图` 按钮加载。

<img src={useBaseUrl("img/dbfirst5.png")} />

### 9.19.3.3 选择表或视图生成

加载表完成后，可以选择您要生成的表或视图，**支持多选**

<img src={useBaseUrl("img/dbfirst6.png")} />

点击底部按钮 `立即生成`

### 9.19.3.4 选择保存目录

点击 `立即生成` 按钮后，会弹出实体保存选择目录资源管理器，默认实体只能保存在 `Furion.Core` 层：

<img src={useBaseUrl("img/dbfirst7.png")} />

点击确定后就可完成所有生成操作。

### 9.19.3.5 生成最终实体代码

<img src={useBaseUrl("img/dbfirst8.png")} />

最终脚本如下：

```shell
PM> &"../tools/cli.ps1"
// -----------------------------------------------------------------------------
//   ______            _______          _
//  |  ____|          |__   __|        | |
//  | |__ _   _ _ __     | | ___   ___ | |___
//  |  __| | | | '__|    | |/ _ \ / _ \| / __|
//  | |  | |_| | |       | | (_) | (_) | \__ \
//  |_|   \__,_|_|       |_|\___/ \___/|_|___/
//
// -----------------------------------------------------------------------------
Furion Tools v1.0.0 启动中......
Furion Tools v1.0.0 启动成功！
Furion Tools v1.0.0 请键入操作类型：[G] 界面操作，[任意字符] 命令行操作
Furion Tools v1.0.0 您的输入是: G
Furion Tools v1.0.0 正在加载数据库表和视图......
Furion Tools v1.0.0 加载成功！
Furion Tools v1.0.0 正在编译解决方案代码......
Build started...
Build succeeded.
For foreign key FK_PersonDetail_Person_PersonId on table dbo.PersonDetail, unable to model the end of the foreign key on principal table dbo.Person. This is usually because the principal table was not included in the selection set.
Furion Tools v1.0.0 编译成功！
Furion Tools v1.0.0 开始生成实体文件......
Furion Tools v1.0.0 正在生成 City.cs 实体代码......
Furion Tools v1.0.0 成功生成 City.cs 实体代码
// -----------------------------------------------------------------------------
// 以下代码由 Furion Tools v1.0.0 生成
// -----------------------------------------------------------------------------

using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;

#nullable disable

namespace Furion.Core
{
    public partial class City : IEntity, IEntityTypeBuilder<City>
    {

        public City()
        {
            InverseParent = new HashSet<City>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public int? ParentId { get; set; }
        public DateTime CreatedTime { get; set; }
        public DateTime? UpdatedTime { get; set; }
        public bool IsDeleted { get; set; }

        public virtual City Parent { get; set; }
        public virtual ICollection<City> InverseParent { get; set; }

        public void Configure(EntityTypeBuilder<City> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
                entityBuilder.HasIndex(e => e.ParentId, "IX_City_ParentId");

                entityBuilder.HasOne(d => d.Parent)
                    .WithMany(p => p.InverseParent)
                    .HasForeignKey(d => d.ParentId);

        }

    }
}

Furion Tools v1.0.0 正在生成 PersonDetail.cs 实体代码......
Furion Tools v1.0.0 成功生成 PersonDetail.cs 实体代码
// -----------------------------------------------------------------------------
// 以下代码由 Furion Tools v1.0.0 生成
// -----------------------------------------------------------------------------

using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;

#nullable disable

namespace Furion.Core
{
    public partial class PersonDetail : IEntity, IEntityTypeBuilder<PersonDetail>
    {

        public int Id { get; set; }
        public string PhoneNumber { get; set; }
        public string Qq { get; set; }
        public int PersonId { get; set; }

        public void Configure(EntityTypeBuilder<PersonDetail> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
                entityBuilder.HasIndex(e => e.PersonId, "IX_PersonDetail_PersonId")
                    .IsUnique();

                entityBuilder.Property(e => e.Qq).HasColumnName("QQ");

        }

    }
}

Furion Tools v1.0.0 正在生成 Post.cs 实体代码......
Furion Tools v1.0.0 成功生成 Post.cs 实体代码
// -----------------------------------------------------------------------------
// 以下代码由 Furion Tools v1.0.0 生成
// -----------------------------------------------------------------------------

using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;

#nullable disable

namespace Furion.Core
{
    public partial class Post : IEntity
    {

        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime CreatedTime { get; set; }
        public DateTime? UpdatedTime { get; set; }
        public bool IsDeleted { get; set; }

    }
}

Furion Tools v1.0.0 正在生成 VPerson.cs 实体代码......
Furion Tools v1.0.0 成功生成 VPerson.cs 实体代码
// -----------------------------------------------------------------------------
// 以下代码由 Furion Tools v1.0.0 生成
// -----------------------------------------------------------------------------

using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;

#nullable disable

namespace Furion.Core
{
    public partial class VPerson : IEntity, IEntityTypeBuilder<VPerson>
    {

        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Address { get; set; }

        public void Configure(EntityTypeBuilder<VPerson> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
                entityBuilder.HasNoKey();

                entityBuilder.ToView("V_Person");

                entityBuilder.Property(e => e.Id).ValueGeneratedOnAdd();

                entityBuilder.Property(e => e.Name).HasMaxLength(32);

        }

    }
}

Furion Tools v1.0.0 全部实体生成成功！
PM>
```

## 9.19.4 命令参数配置

`Furion Tools Cli` 支持多个参数配置，使用方法只需要在命令后面添加即可，如：

```shell
 &"../tools/cli.ps1" -Context 数据库上下文名 -ConnectionName 连接字符串Key
```

支持参数如下：

- `-Tables`：配置要生成的数据库表，数组类型，如果为空，则生成数据库所有表和视图。如：`-Tables Person,PersonDetails`
- `-Context`：配置数据库上下文，默认 `FurionDbContext`，如果有多个数据库上下文，则此参数必须配置
- `-ConnectionName`：配置数据库连接字符串，对应 `appsetting.json` 中的 `ConnectionStrings` 定义的 `Key`
- `-OutputDir`：生成实体代码输出目录，默认为：`./Furion.Core/Entities/`
- `-DbProvider`：数据库提供器，默认是 `Microsoft.EntityFrameworkCore.SqlServer`，其他数据库请指定对应程序集
  - `SqlServer`：`Microsoft.EntityFrameworkCore.SqlServer`
  - `Sqlite`：`Microsoft.EntityFrameworkCore.Sqlite`
  - `Cosmos`：`Microsoft.EntityFrameworkCore.Cosmos`
  - `InMemoryDatabase`：`Microsoft.EntityFrameworkCore.InMemory`
  - `MySql`：`Pomelo.EntityFrameworkCore.MySql` 或 `MySql.EntityFrameworkCore`
  - `PostgreSQL`：`Npgsql.EntityFrameworkCore.PostgreSQL`
  - `Oracle`：`Oracle.EntityFrameworkCore`
  - `Dm`：`Microsoft.EntityFrameworkCore.Dm`
- `-EntryProject`：Web 启用项目层名，默认 `Furion.Web.Entry`
- `-CoreProject`：实体项目层名，默认 `Furion.Core`
- `-DbContextLocators`：多数据库上下文定位器，默认 `MasterDbContextLocator`，支持多个，如：`MasterDbContextLocator,MySqlDbContextLocator`
- `-Product`：解决方案默认前缀，如 `Furion`
- `-UseDatabaseNames`：是否保持生成和数据库、表一致的名称
- `-Namespace`：指定实体命名空间

## 9.19.5 反馈与建议

:::note 与我们交流

给 Furion 提 [Issue](https://gitee.com/dotnetchina/Furion/issues/new?issue)。

:::
